//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package xmpp.androidpush.service;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;

import org.jivesoftware.smack.packet.Message;

import java.util.concurrent.atomic.AtomicBoolean;

import xmpp.androidpush.aidl.IPushBinder;
import xmpp.androidpush.aidl.IPushListener;
import xmpp.androidpush.aidl.PushIqMessage;
import xmpp.androidpush.aidl.PushMessage;
import xmpp.androidpush.aidl.IPushBinder.Stub;
import xmpp.androidpush.aidl.PushListener.PushCallback;
import xmpp.androidpush.util.ConnectionState;
import xmpp.androidpush.util.XmppHelper;

public abstract class PushService extends Service {
    static final String ACTION_DISCONNECT = "xmpp.androidpush.service.disconnect";
    static final String ACTION_RECONNECT = "xmpp.androidpush.service.reconnect";
    static final String ACTION_START = "xmpp.androidpush.service.start";
    static final String ACTION_CHECK_ALARM = "xmpp.androidpush.service.CHECK_ALARM";
    private static final String ACTION_RECONNECT_ALARM = "xmpp.androidpush.service.RECONNECT_ALARM";
    private static final int RECONNECT_AFTER = 5;
    private static final int RECONNECT_MAXIMUM = 600;
    private static final String EXTRA_XMPP_CONFIG = "xmpp_config";
    private static final int ALARM_CODE = 124;
    private static final int ALARM_CHECK = 125;
    private AtomicBoolean mIsConnected = new AtomicBoolean(false);
    private Smackable mSmackable;
    private int mReconnectTimeout = 5;
    private Stub mPushBinder;
    private RemoteCallbackList<IPushListener> mListeners = new RemoteCallbackList();
    private PushConfig mConfig;

    public PushService() {
    }

    public static <T extends PushService> void startService(Context ctx, Class<T> clazz, PushConfig config) {
        Intent intent = new Intent(ctx, clazz);
        intent.setAction(ACTION_START);
        intent.putExtra(EXTRA_XMPP_CONFIG, config);
        PushConfig.setStartUp(ctx, true);
        PushConfig.saveXmppConfig(ctx, config);
        ctx.startService(intent);
    }

    public static <T extends PushService> void bindService(Context ctx, Class<T> clazz,ServiceConnection conn) {
        Intent intent = new Intent(ctx, clazz);
        ctx.bindService(intent,conn,Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
    }

    public static <T extends PushService> void stopService(Context ctx, Class<T> clazz) {
        PushConfig.setStartUp(ctx, false);
        ctx.stopService(new Intent(ctx, clazz));
    }

    public static <T extends PushService> void unbindService(Context ctx, ServiceConnection conn) {
        PushConfig.setStartUp(ctx, false);
        ctx.unbindService(conn);
    }

    public void onCreate() {
        super.onCreate();
        PushReceiver.initNetworkStatus(this.getApplicationContext());
        this.mPushBinder = new PushService.PushStubImpl();
    }

    public void onDestroy() {
        super.onDestroy();
        if(mSmackable.getConnection()!=null){
            mSmackable.getConnection().disconnect();
            mSmackable=null;
        }
        this.updateReconnectAlarm(false);
        this.performDisconnect();
    }

    public final int onStartCommand(Intent intent, int flags, int startId) {

        if(intent != null) {
            if(ACTION_DISCONNECT.equals(intent.getAction())) {
                this.onDisconnected("Network is unreachable");
                return START_STICKY;
            }

            if(ACTION_RECONNECT.equals(intent.getAction())) {
                this.mReconnectTimeout = RECONNECT_AFTER;
                this.doConnect();
                return START_STICKY;
            }

            if(ACTION_RECONNECT_ALARM.equals(intent.getAction())) {
                if(this.mIsConnected.get()) {
                    return START_STICKY;
                }
            } else {
                if(ACTION_START.equals(intent.getAction())) {
                    if(intent.hasExtra(EXTRA_XMPP_CONFIG)) {
                        this.mConfig = (PushConfig)intent.getSerializableExtra(EXTRA_XMPP_CONFIG);
                    }

                    this.doConnect();
                    return START_STICKY;
                }

                if(ACTION_CHECK_ALARM.equals(intent.getAction())) {
                    this.updateCheckAlarm();
                    if(this.mIsConnected.get()) {
                        return START_STICKY;
                    }
                }
            }
        }

        if(mSmackable.getConnection()!=null){
            mSmackable.getConnection().disconnect();
            mSmackable=null;
        }
        this.doConnect();
        return START_STICKY;
    }

    public final IBinder onBind(Intent intent) {
        return this.mPushBinder;
    }

    private void checkXmppConfig() {
        if(this.mConfig == null) {
            this.mConfig = PushConfig.getInstance(this);
        }

    }

    private void doConnect() {
        this.checkXmppConfig();
        if(this.mSmackable == null) {
            this.mSmackable = new SmackableImp(this, this.mConfig);
            this.mSmackable.registerCallback(new PushService.SmackImpListener());
        }

        if(this.mSmackable.getConnectionState() != ConnectionState.ONLINE) {
            this.mSmackable.requestConnectionState(ConnectionState.ONLINE);
        }

    }

    private NetworkInfo getNetworkInfo() {
        Context ctx = this.getApplicationContext();
        ConnectivityManager connMgr = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
        return connMgr.getActiveNetworkInfo();
    }

    private boolean networkConnected() {
        NetworkInfo info = this.getNetworkInfo();
        return info != null && info.isConnected();
    }

    private void performDisconnect() {
        if(this.mSmackable != null) {
            this.mSmackable.unregisterCallback();
            this.mSmackable = null;
        }

    }

    private void onDisconnected(String msg) {
        boolean connstartup = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PushConfig.CONN_STARTUP, false);
        if(!this.networkConnected() && this.mSmackable != null && connstartup) {
            this.updateReconnectAlarm(false);
        } else if(this.mSmackable != null && connstartup) {
            this.updateReconnectAlarm(true);
            this.mReconnectTimeout *= 2;
            if(this.mReconnectTimeout > RECONNECT_MAXIMUM) {
                this.mReconnectTimeout = RECONNECT_MAXIMUM;
            }
        }

    }

    private void updateReconnectAlarm(boolean isNew) {
        Intent intent = new Intent(this, this.getClass());
        intent.setAction(ACTION_RECONNECT_ALARM);
        AlarmManager alm = (AlarmManager)this.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent;
        if(isNew) {
            pendingIntent = PendingIntent.getService(this.getApplicationContext(), ALARM_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            long time = (long)(this.mReconnectTimeout * 1000);
            Log.i("PushService", "ReconnectAlarm, Delay:" + time);
            alm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
        } else {
            pendingIntent = PendingIntent.getService(this.getApplicationContext(), ALARM_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            alm.cancel(pendingIntent);
        }

    }

    private void updateCheckAlarm() {
        Intent intent = new Intent(ACTION_CHECK_ALARM);
        AlarmManager alm = (AlarmManager)this.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), ALARM_CHECK, intent,  PendingIntent.FLAG_UPDATE_CURRENT);
        alm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 3600000L, pendingIntent);
    }

    protected final ConnectionState getConnectState() {
        ConnectionState cs = ConnectionState.OFFLINE;
        if(this.mSmackable != null) {
            cs = this.mSmackable.getConnectionState();
        }

        return cs;
    }

    private void broadcastMessage(PushMessage msg) {
        int broadCastItems = this.mListeners.beginBroadcast();

        for(int i = 0; i < broadCastItems; ++i) {
            try {
                ((IPushListener)this.mListeners.getBroadcastItem(i)).receivedMessage(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        this.mListeners.finishBroadcast();
    }
    private void broadcastMessage(String msg) {
        int broadCastItems = this.mListeners.beginBroadcast();

        for(int i = 0; i < broadCastItems; ++i) {
            try {
                ((IPushListener)this.mListeners.getBroadcastItem(i)).receivedIqMessage(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        this.mListeners.finishBroadcast();
    }

    private void broadcastState(ConnectionState state, String msg) {
        int broadCastItems = this.mListeners.beginBroadcast();

        for(int i = 0; i < broadCastItems; ++i) {
            try {
                ((IPushListener)this.mListeners.getBroadcastItem(i)).connectionChanged(state.ordinal(), msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        this.mListeners.finishBroadcast();
    }

    protected final void sendMessage(PushMessage msg) {
        if(this.mSmackable != null) {
            this.mSmackable.sendMessage(msg.toMessage());
        }

    }
    protected final void sendIqMessage(String msg) {
        if(msg!= null) {
            this.mSmackable.sendIqMessage(msg);
        }

    }

    protected abstract boolean receiveMessage(PushMessage msg);

    protected abstract void sendOfflineMessage();

    public class PushStubImpl extends IPushBinder.Stub {
        public PushStubImpl() {
        }

        public void sendMessage(PushMessage msg) throws RemoteException {
            PushService.this.sendMessage(msg);
        }

        @Override
        public void sendIqMessage(String msg) throws RemoteException {
            PushService.this.sendIqMessage(msg);
        }

        public boolean isConnected() throws RemoteException {
            return PushService.this.getConnectState() == ConnectionState.ONLINE;
        }

        public void registerPushListener(IPushListener listener) throws RemoteException {
            if(listener != null) {

                PushService.this.mListeners.register(listener);
            }

        }

        public void unregisterPushListener(IPushListener listener) throws RemoteException {
            if(listener != null) {
                PushService.this.mListeners.unregister(listener);
            }

        }
    }

    public class SmackImpListener implements PushCallback {
        public SmackImpListener() {
        }

        public void receivedMessage(PushMessage msg) {

            if(!XmppHelper.isEmpty(msg.getMsg()) || !msg.getPropertyNames().isEmpty()) {
                if(PushService.this.receiveMessage(msg)) {
                    PushService.this.broadcastMessage(msg);
                }
            }
        }

        @Override
        public void receivedIqMessage(String msg) {

            if(!XmppHelper.isEmpty(msg)) {
                if(PushService.this.receiveIqMessage(msg)) {
                    PushService.this.broadcastMessage(msg);
                }
            }
        }

        public void connectionChanged(ConnectionState state, String msg) {
            PushService.this.mIsConnected.set(state == ConnectionState.ONLINE);
            if(state == ConnectionState.ONLINE) {
                PushService.this.sendOfflineMessage();
            } else {
                PushService.this.onDisconnected(msg);
            }

            PushService.this.broadcastState(state, msg);
        }
    }

    protected abstract boolean receiveIqMessage(String msg);
}
